package javax.core.common.utils;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * 泛型操作类
 *
 * @author raos
 * @emil 991207823@qq.com
 * @date 2021/8/30 21:12
 */
@SuppressWarnings("unchecked")
public class GenericsUtils {
    private static final Log logger = LogFactory.getLog(GenericsUtils.class);

    /** 无参构造*/
    private GenericsUtils() { }

    /**
     * 通过反射,获得定义Class时声明的父类的范型参数的类型. 如public BookManager extends GenricManager<Book>
     *
     * @param clazz 类类型
     * @return 第一个泛型声明，如果不能确定，则为：Object.class
     */
    public static Class getSuperClassGenericsType(Class clazz) {
        return getSuperClassGenericsType(clazz, 0);
    }

    /**
     * 通过反射,获得定义Class时声明的父类的范型参数的类型. 如public BookManager extends GenricManager<Book>
     *
     * @param clazz 类类型
     * @param index 泛型d声明的索引，从0开始。
     * @return 索引泛型声明，如果不能确定的，则为：Object.class
     */
    public static Class getSuperClassGenericsType(Class clazz, int index) {
        // 由这个类表示的实体(类、接口、原始类型或void)的直接超类的Type
        Type genType = clazz.getGenericSuperclass();
        // 判断是否是一个参数化类型
        if (!(genType instanceof ParameterizedType)) {
            logger.debug(clazz.getSimpleName() + "'s superclass not ParameterizedType");
            return Object.class;
        }
        // 获取该类型的实际类型参数的 Type 对象数组。
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
        // 判断索引值是否 >= 或 无效的 Type 数组长度
        if (index >= params.length || index < 0) {
            logger.warn("Index: " + index + ", Size of " + clazz.getSimpleName()
                    + "'s Parameterized Type: " + params.length);
            return Object.class;
        }
        // 判断指定索引的对象的类类型是否为Class.
        if (!(params[index] instanceof Class)) {
            logger.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
            return Object.class;
        }
        return (Class) params[index];
    }

}
